package com.test;

import com.test.scope.ObjectFactory;
import com.test.scope.Scope;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 单例范围类，确保每个bean只有一个实例
 */
public class SingletonScope implements Scope {

    // 存储单例对象的容器
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    // 存储销毁回调函数的容器
    private final Map<String, Runnable> destructionCallbacks = new ConcurrentHashMap<>(16);

    /**
     * 获取单例对象
     * 如果容器中没有该对象，将调用objectFactory创建并放入容器
     * 
     * @param name bean的名称
     * @param objectFactory bean的创建工厂
     * @return 返回创建或已存在的bean实例
     */
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Object bean = this.singletonObjects.get(name);
        if (bean == null){
            try{
                bean = objectFactory.getObject();
                this.singletonObjects.put(name, bean);
            }catch (Exception e){
                throw e;
            }
        }
        return bean;
    }

    /**
     * 移除并返回存储在容器中的bean实例
     * 同时移除对应的销毁回调函数
     * 
     * @param name 要移除的bean的名称
     * @return 返回被移除的bean实例，如果没有则返回null
     */
    @Override
    public Object remove(String name) {
        Object bean = this.singletonObjects.remove(name);
        this.destructionCallbacks.remove(name);
        return bean;
    }

    /**
     * 注册bean的销毁回调函数
     * 
     * @param name bean的名称
     * @param callback 销毁回调函数
     */
    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        this.destructionCallbacks.put(name, callback);
    }

    /**
     * 返回单例范围的标识符
     * 
     * @return 返回字符串"singleton"
     */
    @Override
    public String getConversationId() {
        return "singleton";
    }

    /**
     * 销毁所有单例对象
     * 调用每个bean的销毁回调函数，并清空容器
     */
    public void destroySingletons(){
        String[] singletonNames = this.singletonObjects.keySet().toArray(new String[0]);
        for (String name : singletonNames){
            Runnable callback = this.destructionCallbacks.remove(name);
            if (callback != null){
                try{
                    callback.run();
                }catch (Exception e){
                    System.err.println("Error while destroying singleton with name '" + name + "'");
                }
            }
        }
        this.singletonObjects.clear();
    }
}
